﻿using System;
using Net.Share;
using Net.Client;
using Cysharp.Threading.Tasks;

public static class ClientExtensions
{
    #region 同步远程调用, 跟Http协议一样, 请求必须有回应 请求和回应方法都是相同的, 都是根据protocol请求和回应
    public static UniTask<RpcModelAsync> Request(this Client self, Enum protocol, params object[] pars)
        => self.Request(NetCmd.CallRpc, (uint)protocol.GetHashCode(), RequestTimeout.FiveSeconds, true, SyncSerialize.False, null, pars);
    public static UniTask<RpcModelAsync> Request(this Client self, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => self.Request(NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, true, SyncSerialize.False, null, pars);
    public static UniTask<RpcModelAsync> Request(this Client self, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => self.Request(NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, intercept, SyncSerialize.False, null, pars);
    public static UniTask<RpcModelAsync> Request(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => self.Request(cmd, (uint)protocol.GetHashCode(), timeout, true, SyncSerialize.False, null, pars);
    public static UniTask<RpcModelAsync> Request(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => self.Request(cmd, (uint)protocol.GetHashCode(), timeout, intercept, SyncSerialize.False, null, pars);
    #endregion

    #region 同步远程调用, 跟Http协议一样, 请求必须有回应 请求和回应方法都是相同的, 都是根据funcAndCb请求和回应
    public static UniTask<T> Request<T>(this Client self, uint protocol, params object[] pars)
        => Request<T>(self, NetCmd.CallRpc, protocol, RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<T> Request<T>(this Client self, uint protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T>(self, NetCmd.CallRpc, protocol, timeout, true, null, pars);
    public static UniTask<T> Request<T>(this Client self, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T>(self, NetCmd.CallRpc, protocol, timeout, intercept, null, pars);
    public static UniTask<T> Request<T>(this Client self, NetCmd cmd, uint protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T>(self, cmd, protocol, timeout, true, null, pars);
    public static UniTask<T> Request<T>(this Client self, NetCmd cmd, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T>(self, cmd, protocol, timeout, intercept, null, pars);

    public static UniTask<T> Request<T>(this Client self, Enum protocol, params object[] pars)
        => Request<T>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<T> Request<T>(this Client self, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, true, null, pars);
    public static UniTask<T> Request<T>(this Client self, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, intercept, null, pars);
    public static UniTask<T> Request<T>(this Client self, NetCmd cmd, Enum protocol, params object[] pars)
        => Request<T>(self, cmd, (uint)protocol.GetHashCode(), RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<T> Request<T>(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T>(self, cmd, (uint)protocol.GetHashCode(), timeout, true, null, pars);
    public static UniTask<T> Request<T>(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T>(self, cmd, (uint)protocol.GetHashCode(), timeout, intercept, null, pars);
    #endregion

    #region 同步远程调用, 跟Http协议一样, 请求必须有回应 请求和回应方法都是相同的, 都是根据funcAndCb请求和回应
    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, uint protocol, params object[] pars)
        => Request<T, T1>(self, NetCmd.CallRpc, protocol, RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, uint protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1>(self, NetCmd.CallRpc, protocol, timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1>(self, NetCmd.CallRpc, protocol, timeout, intercept, null, pars);
    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, NetCmd cmd, uint protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1>(self, cmd, protocol, timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, NetCmd cmd, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1>(self, cmd, protocol, timeout, intercept, null, pars);

    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, Enum protocol, params object[] pars)
        => Request<T, T1>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, intercept, null, pars);
    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, NetCmd cmd, Enum protocol, params object[] pars)
        => Request<T, T1>(self, cmd, (uint)protocol.GetHashCode(), RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1>(self, cmd, (uint)protocol.GetHashCode(), timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1>> Request<T, T1>(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1>(self, cmd, (uint)protocol.GetHashCode(), timeout, intercept, null, pars);
    #endregion

    #region 同步远程调用, 跟Http协议一样, 请求必须有回应 请求和回应方法都是相同的, 都是根据funcAndCb请求和回应
    public static UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(this Client self, uint protocol, params object[] pars)
        => Request<T, T1, T2>(self, NetCmd.CallRpc, protocol, RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(this Client self, uint protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2>(self, NetCmd.CallRpc, protocol, timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(this Client self, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2>(self, NetCmd.CallRpc, protocol, timeout, intercept, null, pars);
    public static UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(this Client self, NetCmd cmd, uint protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2>(self, cmd, protocol, timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(this Client self, NetCmd cmd, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2>(self, cmd, protocol, timeout, intercept, null, pars);

    public static UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(this Client self, Enum protocol, params object[] pars)
        => Request<T, T1, T2>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(this Client self, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(this Client self, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, intercept, null, pars);
    public static UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2>(self, cmd, (uint)protocol.GetHashCode(), timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2>(self, cmd, (uint)protocol.GetHashCode(), timeout, intercept, null, pars);
    #endregion

    #region 同步远程调用, 跟Http协议一样, 请求必须有回应 请求和回应方法都是相同的, 都是根据funcAndCb请求和回应
    public static UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(this Client self, uint protocol, params object[] pars)
        => Request<T, T1, T2, T3>(self, NetCmd.CallRpc, protocol, RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(this Client self, uint protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2, T3>(self, NetCmd.CallRpc, protocol, timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(this Client self, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2, T3>(self, NetCmd.CallRpc, protocol, timeout, intercept, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(this Client self, NetCmd cmd, uint protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2, T3>(self, cmd, protocol, timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(this Client self, NetCmd cmd, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2, T3>(self, cmd, protocol, timeout, intercept, null, pars);

    public static UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(this Client self, Enum protocol, params object[] pars)
        => Request<T, T1, T2, T3>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(this Client self, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2, T3>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(this Client self, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2, T3>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, intercept, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2, T3>(self, cmd, (uint)protocol.GetHashCode(), timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2, T3>(self, cmd, (uint)protocol.GetHashCode(), timeout, intercept, null, pars);
    #endregion

    #region 同步远程调用, 跟Http协议一样, 请求必须有回应 请求和回应方法都是相同的, 都是根据funcAndCb请求和回应
    public static UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(this Client self, uint protocol, params object[] pars)
        => Request<T, T1, T2, T3, T4>(self, NetCmd.CallRpc, protocol, RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(this Client self, uint protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2, T3, T4>(self, NetCmd.CallRpc, protocol, timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(this Client self, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2, T3, T4>(self, NetCmd.CallRpc, protocol, timeout, intercept, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(this Client self, NetCmd cmd, uint protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2, T3, T4>(self, cmd, protocol, timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(this Client self, NetCmd cmd, uint protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2, T3, T4>(self, cmd, protocol, timeout, intercept, null, pars);

    public static UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(this Client self, Enum protocol, params object[] pars)
        => Request<T, T1, T2, T3, T4>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), RequestTimeout.FiveSeconds, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(this Client self, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2, T3, T4>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(this Client self, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2, T3, T4>(self, NetCmd.CallRpc, (uint)protocol.GetHashCode(), timeout, intercept, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, params object[] pars)
        => Request<T, T1, T2, T3, T4>(self, cmd, (uint)protocol.GetHashCode(), timeout, true, null, pars);
    public static UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(this Client self, NetCmd cmd, Enum protocol, in RequestTimeout timeout, bool intercept, params object[] pars)
        => Request<T, T1, T2, T3, T4>(self, cmd, (uint)protocol.GetHashCode(), timeout, intercept, null, pars);
    #endregion

    private static async UniTask<T> Request<T>(Client self, NetCmd cmd, uint protocol, RequestTimeout timeout, bool intercept, byte[] buffer, params object[] pars)
    {
        var task = await self.Request(cmd, protocol, timeout, intercept, SyncSerialize.False, buffer, pars);
        if (!task.IsCompleted)
            return default;
        return (T)task.model.Pars[0];
    }

    private static async UniTask<ValueTuple<T, T1>> Request<T, T1>(Client self, NetCmd cmd, uint protocol, RequestTimeout timeout, bool intercept, byte[] buffer, params object[] pars)
    {
        var task = await self.Request(cmd, protocol, timeout, intercept, SyncSerialize.False, buffer, pars);
        if (!task.IsCompleted)
            return new ValueTuple<T, T1>(default, default);
        return new ValueTuple<T, T1>((T)task.model.Pars[0], (T1)task.model.Pars[1]);
    }

    private static async UniTask<ValueTuple<T, T1, T2>> Request<T, T1, T2>(Client self, NetCmd cmd, uint protocol, RequestTimeout timeout, bool intercept, byte[] buffer, params object[] pars)
    {
        var task = await self.Request(cmd, protocol, timeout, intercept, SyncSerialize.False, buffer, pars);
        if (!task.IsCompleted)
            return new ValueTuple<T, T1, T2>(default, default, default);
        return new ValueTuple<T, T1, T2>((T)task.model.Pars[0], (T1)task.model.Pars[1], (T2)task.model.Pars[2]);
    }

    private static async UniTask<ValueTuple<T, T1, T2, T3>> Request<T, T1, T2, T3>(Client self, NetCmd cmd, uint protocol, RequestTimeout timeout, bool intercept, byte[] buffer, params object[] pars)
    {
        var task = await self.Request(cmd, protocol, timeout, intercept, SyncSerialize.False, buffer, pars);
        if (!task.IsCompleted)
            return new ValueTuple<T, T1, T2, T3>(default, default, default, default);
        return new ValueTuple<T, T1, T2, T3>((T)task.model.Pars[0], (T1)task.model.Pars[1], (T2)task.model.Pars[2], (T3)task.model.Pars[3]);
    }

    private static async UniTask<ValueTuple<T, T1, T2, T3, T4>> Request<T, T1, T2, T3, T4>(Client self, NetCmd cmd, uint protocol, RequestTimeout timeout, bool intercept, byte[] buffer, params object[] pars)
    {
        var task = await self.Request(cmd, protocol, timeout, intercept, SyncSerialize.False, buffer, pars);
        if (!task.IsCompleted)
            return new ValueTuple<T, T1, T2, T3, T4>(default, default, default, default, default);
        return new ValueTuple<T, T1, T2, T3, T4>((T)task.model.Pars[0], (T1)task.model.Pars[1], (T2)task.model.Pars[2], (T3)task.model.Pars[3], (T4)task.model.Pars[4]);
    }

    #region 远程过程调用扩展
    public static void Call(this Client self, Enum protocol, params object[] pars) => self.Call((uint)protocol.GetHashCode(), pars);
    public static void Call(this Client self, NetCmd cmd, Enum protocol, params object[] pars) => self.Call(cmd, (uint)protocol.GetHashCode(), pars);
    #endregion

    public static void DispatchRpc(this Client self, Enum protocol, params object[] pars) => self.DispatchRpc((uint)protocol.GetHashCode(), pars);

    public static void AddRpc(this Client self, object target, AddRpcMode mode = AddRpcMode.None) => self.RpcAdapter.AddRpc(target, mode);
    public static void RemoveRpc(this Client self, object target) => self.RpcAdapter.RemoveRpc(target);
}